package cn.wp.ewallet.wallet.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.wp.common.core.authentication.AuthenticationContext;
import cn.wp.common.core.model.WpPage;
import cn.wp.common.core.util.BeanUtil;
import cn.wp.common.core.dto.WpResult;
import cn.wp.common.core.id.Id;
import cn.wp.ewallet.common.model.dto.ConverRuleDictDto;
import cn.wp.ewallet.common.model.dto.MoneyTypeInfoDto;
import cn.wp.ewallet.common.service.ConverRoleDictService;
import cn.wp.ewallet.common.service.MoneyTypeInfoService;
import cn.wp.ewallet.wallet.dao.*;
import cn.wp.ewallet.wallet.extension.constant.EwalletWalletConstant;
import cn.wp.ewallet.wallet.extension.util.EwalletWalletUtil;
import cn.wp.ewallet.wallet.model.dto.*;
import cn.wp.ewallet.wallet.model.entity.*;
import cn.wp.ewallet.wallet.service.AccountInfoService;
import cn.wp.ewallet.wallet.service.ExchangeMoneyInfoService;
import cn.wp.ewallet.wallet.service.UserWalletRelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import static cn.wp.ewallet.wallet.extension.constant.EwalletWalletConstant.*;


/**
 * 兑换申请单-业务逻辑层实现
 * Created by zhangyongli on 2020/01/09
 */
@Slf4j
@Service
public class ExchangeMoneyInfoServiceImpl implements ExchangeMoneyInfoService {

    @Autowired
    private ExchangeMoneyInfoDao exchangeMoneyInfoDao;

    @Autowired
    private ReqOrderInfoDao reqOrderInfoDao;

    @Autowired
    private ProcRecordInfoDao procRecordInfoDao;

    @Autowired
    private ExchangeProcInfoDao exchangeProcInfoDao;

    @Autowired
    private ConverRoleDictService converRoleDictService;

    @Autowired
    private AuthenticationContext authenticationContext;

    @Autowired
    private AccountInfoDao accountInfoDao;

    @Autowired
    private AccountInfoService accountInfoService;

    @Autowired
    private UserWalletRelService userWalletRelService;

    @Autowired
    private MoneyTypeInfoService moneyTypeInfoService;

    /**
     * 查询单个兑换申请单
     *
     * @param orderId
     * @return
     */
    @Override
    public ExchangeMoneyInfoDto getExchangeMoneyReqOrderById(String orderId) {
        ExchangeMoneyInfoDoo exchangeMoneyInfoDoo = exchangeMoneyInfoDao.selectExchangeMoneyReqOrderById(orderId);
        //查询SHQC数据精度
        MoneyTypeInfoDto shqc = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(MONEY_TYPE_SHQC);
        BigDecimal shqcUnit = BigDecimal.valueOf(Long.valueOf(shqc.getMoneyTypeUnit()));
        //查询USDT数据精度
        MoneyTypeInfoDto usdt = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(MONEY_TYPE_USDT);
        BigDecimal usdtUnit = BigDecimal.valueOf(Long.valueOf(usdt.getMoneyTypeUnit()));

        return BeanUtil.copyProperties(exchangeMoneyInfoDoo, ExchangeMoneyInfoDto.class, new BeanUtil.Processor<ExchangeMoneyInfoDoo, ExchangeMoneyInfoDto>() {
            @Override
            public void convert(ExchangeMoneyInfoDoo source, ExchangeMoneyInfoDto target) {
                if (null != source.getExchangeAmount()){
                    target.setExchangeAmount(EwalletWalletUtil.toUpperWei(source.getExchangeAmount(), shqcUnit));
                }
                if (null != source.getMoneyAmount()) {
                    target.setMoneyAmount(EwalletWalletUtil.toUpperWei(source.getMoneyAmount(), usdtUnit));
                }
                target.setCreateDate(DateUtil.formatDateTime(source.getCreateDate()));
                target.setOperTime(DateUtil.formatDateTime(source.getOperTime()));
            }
        });
    }

    /**
     * 查询兑换交易记录
     *
     * @return
     */
    @Override
    public WpPage<ExchangeMoneyInfoDto> getExchangeMoneyReqOrderByaddress(WpPage page) {
        UserWalletRelDto userWalletRelDto = userWalletRelService.getUserWalletRel();
        WpPage<ExchangeMoneyInfoDoo> wpPage = exchangeMoneyInfoDao.selectExchangeMoneyReqOrderByaddress(userWalletRelDto.getWalletAddress(), page);

        //查询SHQC数据精度
        MoneyTypeInfoDto shqc = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(MONEY_TYPE_SHQC);
        BigDecimal shqcUnit = BigDecimal.valueOf(Long.valueOf(shqc.getMoneyTypeUnit()));
        //查询USDT数据精度
        MoneyTypeInfoDto usdt = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(MONEY_TYPE_USDT);
        BigDecimal usdtUnit = BigDecimal.valueOf(Long.valueOf(usdt.getMoneyTypeUnit()));

        return wpPage.doConvertDto(ExchangeMoneyInfoDto.class, new BeanUtil.Processor<ExchangeMoneyInfoDoo, ExchangeMoneyInfoDto>() {
            @Override
            public void convert(ExchangeMoneyInfoDoo source, ExchangeMoneyInfoDto target) {
                if (null != source.getExchangeAmount()){
                    target.setExchangeAmount(EwalletWalletUtil.toUpperWei(source.getExchangeAmount(), shqcUnit));
                }
                if (null != source.getMoneyAmount()) {
                    target.setMoneyAmount(EwalletWalletUtil.toUpperWei(source.getMoneyAmount(), usdtUnit));
                }
                target.setCreateDate(DateUtil.formatDateTime(source.getCreateDate()));
                target.setOperTime(DateUtil.formatDateTime(source.getOperTime()));
            }
        });
    }

    /**
     * 添加兑换申请单
     *
     * @param exchangeMoneyReqDto
     * @return
     */
    @Override
    @Transactional
    public synchronized WpResult addExchangeMoneyInfo(ExchangeMoneyReqDto exchangeMoneyReqDto) {


        try {
            //兑换的地址 通过token获取
            UserWalletRelDto userWalletRelDto = userWalletRelService.getUserWalletRel();

            //查询USDT的余额
            AccountInfoDoo accountInfoDoo = accountInfoDao.selectAccountByWalletAddMoneyTypeId(userWalletRelDto.getWalletAddress(), exchangeMoneyReqDto.getTurnMoneyType(), ACCOUNT_TYPE_AVAILABLE);
            //兑换的金额
            BigDecimal money = EwalletWalletUtil.toLowerWei(exchangeMoneyReqDto.getMoneyAmount(), new BigDecimal(accountInfoDoo.getMoneyTypeUnit()));
            //USDT余额
            BigDecimal blance = accountInfoDoo.getMoneyAmount();
            //表示 更新后的USDT 额度  --->兑换申请扣除的USDT额度
            BigDecimal afterUSDT = blance.subtract(money);
            if (afterUSDT.compareTo(BigDecimal.ZERO) == -1) {
                return new WpResult().failure(CHECK_AMOUNT_FAILED_CODE, "账户余额不足");
            }
            //保证账户资产变动信息
            accountInfoService.saveAccountChange(accountInfoDoo.getWalletAddress(), money, ACCOUNT_SUBTRACT, ACCOUNT_CHARGE_CASE_EXCHANGE, exchangeMoneyReqDto.getTurnMoneyType(), ACCOUNT_TYPE_AVAILABLE);

            //保存申请单
            ReqOrderInfoDo reqOrderInfoDo = createReqOrderInfo(accountInfoDoo.getAccountId(), accountInfoDoo.getWalletAddress());
            //保存兑换申请详细信息
            exchangeMoneyReqDto.setMoneyAmount(money);
            createtExchangeMoneyInfoDo(reqOrderInfoDo.getReqOrderId(), exchangeMoneyReqDto);

            return new WpResult().success();
        }catch (Exception e){
            log.error("兑换失败");
            e.printStackTrace();
            return new WpResult().failure();
        }
    }

    /**
     * 处理兑换逻辑
     *
     * @param exchangeMoneyDto
     * @return
     */
    @Transactional
    @Override
    public synchronized WpResult handleExchangeMoneyOrder(ExchangeMoneyDto exchangeMoneyDto) {
        ExchangeMoneyInfoDoo exchangeMoneyInfoDoo = exchangeMoneyInfoDao.selectExchangeMoneyReqOrderById(exchangeMoneyDto.getReqOrderId());
        if (null == exchangeMoneyInfoDoo || !EwalletWalletConstant.REQ_ORDER_STATUS_PENDING.equals(exchangeMoneyInfoDoo.getOrderStatus())) {
            log.info("订单不存在，或者订单状态不是待处理，订单ID={}", exchangeMoneyInfoDoo.getReqOrderId());
            return new WpResult().failure(1,"订单不存在，或者订单状态不是待处理");
        }

        //USDT账户
        MoneyTypeInfoDto usdtType = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(exchangeMoneyInfoDoo.getTurnMoneyType());

        //SHQC账户
        MoneyTypeInfoDto shqcType = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(exchangeMoneyInfoDoo.getExchangeMoneyType());

        //计算可兑换的SHQC数量
        ConverRuleDictDto converRuleDictDto = converRoleDictService.getConverRuleDict(exchangeMoneyInfoDoo.getTurnMoneyType(), exchangeMoneyInfoDoo.getExchangeMoneyType(), exchangeMoneyDto.getConverType());
        if (null == converRuleDictDto) {
            log.info("兑换条件异常，订单ID={}，兑换条件={}", exchangeMoneyInfoDoo.getReqOrderId(), exchangeMoneyDto.getConverType());
            return new WpResult().failure(2,"兑换条件异常");
        }

        BigDecimal shqcAmount = BigDecimal.valueOf(0);
        String exchangeRate = converRuleDictDto.getExchangeRate();
        if (StringUtils.isNotEmpty(exchangeRate)) {
            String[] rates = exchangeRate.split(":");
            BigDecimal rate = BigDecimal.valueOf(Double.valueOf(rates[1])).divide(BigDecimal.valueOf(Double.valueOf(rates[0])));
            shqcAmount =  EwalletWalletUtil.toUpperWei(exchangeMoneyInfoDoo.getMoneyAmount(), new BigDecimal(usdtType.getMoneyTypeUnit())).multiply(rate);
        }
        shqcAmount = EwalletWalletUtil.toLowerWei(shqcAmount, new BigDecimal(shqcType.getMoneyTypeUnit()));
        accountInfoService.saveAccountChange(exchangeMoneyInfoDoo.getWalletAddress(), shqcAmount, ACCOUNT_ADD, ACCOUNT_CHARGE_CASE_EXCHANGE, exchangeMoneyInfoDoo.getExchangeMoneyType(), ACCOUNT_TYPE_AVAILABLE);

        //更新申请单状态
        ReqOrderInfoDo reqOrderInfoDo = new ReqOrderInfoDo();
        reqOrderInfoDo.setOrderStatus(REQ_ORDER_STATUS_FINISH);//兑换的申请单的状态
        reqOrderInfoDo.setReqOrderId(exchangeMoneyDto.getReqOrderId());
        reqOrderInfoDo.setRemark("兑换处理完成");
        reqOrderInfoDao.updateReqOrderInfo(reqOrderInfoDo);

        //保存兑换处理记录
        ProcRecordInfoDo procRecordInfoDo = new ProcRecordInfoDo(Id.gen(), reqOrderInfoDo.getReqOrderId(), ACCOUNT_CHANGE_SUCCESS, authenticationContext.currentUser().getId(), new Date(), "兑换处理成功");
        procRecordInfoDao.saveProcRecordInfo(procRecordInfoDo);

        //保存兑换处理详细信息
        ExchangeProcInfoDo exchangeProcInfoDo = new ExchangeProcInfoDo(procRecordInfoDo.getProcRecordId(), shqcAmount, converRuleDictDto.getRuleId(), exchangeRate);
        exchangeProcInfoDao.saveExchangeProInfo(exchangeProcInfoDo);
        return new WpResult().success(true);
    }


    @Override
    public BigDecimal calculateUsdtToShqc(UsdtExchangeShqcDto usdtExchangeShqcDto) {
        //查询汇率
        ConverRuleDictDto converRuleDictDto = converRoleDictService.getConverRuleDict(EwalletWalletConstant.MONEY_TYPE_USDT, EwalletWalletConstant.MONEY_TYPE_SHQC, usdtExchangeShqcDto.getConverType());
        if (null == converRuleDictDto) {
            return null;
        }
        String exchangeRate = converRuleDictDto.getExchangeRate();
        if (StringUtils.isNotEmpty(exchangeRate)) {
            String[] rates = exchangeRate.split(":");
            BigDecimal rate = BigDecimal.valueOf(Double.valueOf(rates[1])).divide(BigDecimal.valueOf(Double.valueOf(rates[0])));
            return usdtExchangeShqcDto.getExchangeAmount().multiply(rate);
        }
        return null;
    }

    /**
     * 保存兑换申请单
     * @param accountId
     * @param walletAddress
     * @return
     */
    private ReqOrderInfoDo createReqOrderInfo(String accountId, String walletAddress) {
        ReqOrderInfoDo reqOrderInfoDo = new ReqOrderInfoDo();
        reqOrderInfoDo.setReqOrderId(Id.gen());
        reqOrderInfoDo.setAccountId(accountId);
        reqOrderInfoDo.setCreateDate(new Date());
        reqOrderInfoDo.setOrderStatus(REQ_ORDER_STATUS_PENDING);
        reqOrderInfoDo.setRemark("兑换申请");
        reqOrderInfoDo.setReqType(REQ_ORDER_TYPE_EXCHANGEMONEY);
        reqOrderInfoDo.setWalletAddress(walletAddress);
        reqOrderInfoDao.insertReqOrderInfo(reqOrderInfoDo);
        return reqOrderInfoDo;
    }

    /**
     * 保存兑换申请详细信息
     * @param reqOrderId
     * @param exchangeMoneyReqDto
     * @return
     */
    private ExchangeMoneyInfoDo createtExchangeMoneyInfoDo(String reqOrderId, ExchangeMoneyReqDto exchangeMoneyReqDto) {
        ExchangeMoneyInfoDo exchangeMoneyInfoDo = new ExchangeMoneyInfoDo();
        exchangeMoneyInfoDo.setReqOrderId(reqOrderId);
        exchangeMoneyInfoDo.setExchangeMoneyType(exchangeMoneyReqDto.getExchangeMoneyType());
        exchangeMoneyInfoDo.setMoneyAmount(exchangeMoneyReqDto.getMoneyAmount());
        exchangeMoneyInfoDo.setTurnMoneyType(exchangeMoneyReqDto.getTurnMoneyType());
        exchangeMoneyInfoDao.insertExchangeMoneyInfo(exchangeMoneyInfoDo);
        return exchangeMoneyInfoDo;
    }

}